package com.swc.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.swc.constant.HeaderConstant;
import com.swc.factory.EncryptModeFactory;
import com.swc.property.SecretKeyProperty;
import com.swc.secret.AbstractSecret;
import com.swc.sign.Sha256Sign;
import com.swc.util.RsaUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;

/**
 * 加密返回的数据
 * @author huyupeng
 * @date 2020-09-18
 */
@Component
public class EncryptRespDataFilter extends ZuulFilter {

    private Logger logger = LoggerFactory.getLogger(EncryptRespDataFilter.class);

    @Autowired
    private SecretKeyProperty rsaKeyProperty;

    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 10;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();

        String respEncrypt = ctx.getRequest().getHeader(HeaderConstant.HEADER_RESP_ENCRYPT);
        if (HttpStatus.SC_OK == ctx.getResponse().getStatus()
                && StringUtils.isNotEmpty(respEncrypt) && !HeaderConstant.HEADER_RESP_ENCRYPT_NONE.equals(respEncrypt)) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String secretKey = ctx.getRequest().getHeader(HeaderConstant.HEADER_SECRET_KEY);
        if (StringUtils.isEmpty(secretKey)) {
            throw new RuntimeException("请求头中没有密钥");
        }
        InputStream stream = ctx.getResponseDataStream();
        AbstractSecret abstractSecret = new EncryptModeFactory().getEncryptMode(ctx.getRequest().getHeader(HeaderConstant.HEADER_ENCRYPT_MODE));
        try {
            String body = StreamUtils.copyToString(stream, StandardCharsets.UTF_8);

            if (StringUtils.isNotEmpty(body)) {
                String decryptSecretKey = RsaUtil.decrypt(secretKey, rsaKeyProperty.getRsaPrivateKey());
                String encryptBody = abstractSecret.encrypt(body, rsaKeyProperty.getRsaPublicKey(), decryptSecretKey);
                Sha256Sign sha256Sign = new Sha256Sign();
                Map<String, String> data = new TreeMap<>();
                data.put("response", encryptBody);
                String sign = sha256Sign.verifySign(data, decryptSecretKey);
                ctx.getResponse().setHeader(HeaderConstant.HEADER_SIGN_KEY, sign);
                String message = "{\"response\":\""+encryptBody+"\",\"sign\":\""+sign+"\"}";
                ctx.setResponseBody(message);
            }
        } catch (Exception e) {
            logger.warn("【网关层返回的数据处理】加密失败", e);
            throw new RuntimeException("网关层加解密数据失败");
        }
        return null;
    }

}
